package main

import (
	//"bufio"
	"encoding/json"
	"fmt"
	"github.com/hoisie/redis"
	//"io"
	"io/ioutil"
	"message"
	//"os"
	//"strconv"
	"strings"
	"time"
	"gopkg.in/yaml.v2"
)

type TestCaseJson struct {
	Message string      `json:"message"`
	Results interface{} `json:"result"`
}

var clientPush redis.Client
var clientGet redis.Client

func checkErr(err error) {
	if err != nil {
		fmt.Println(err.Error())
		return
	}
}

func verifyRedisKeyValue(key, value, status string) {

	if status == "update" {
		if ok, _ := clientGet.Exists(key); !ok {
			fmt.Println("the key " + key + " is not exists. FAILED")
			return
		}

		if rValue, err := clientGet.Get(key); err != nil {
			fmt.Println("get the key " + key + " value FAILED")
		} else {
			if strings.EqualFold(string(rValue), value) {
				fmt.Println("the key " + key + " verify PASSED")
			} else {
				fmt.Println("the key " + key + " verify FAILED")
				fmt.Println("please check infact value : " + string(rValue))
				fmt.Println("expect value :" + value)
			}
		}
	} else {
		if ok, _ := clientGet.Exists(key); ok {
			fmt.Println("the key " + key + " is exists. FAILED")
		} else {
			fmt.Println("the key " + key + " is not exists now. PASSED")
		}
	}
}

func verifyRedisSetHashKeyValue(key string, value []interface{}, status string) {

	if key != "domains" && status == "delete" {
		if strings.HasPrefix(key, "targeting") && strings.Contains(key, "area") {
			if ok, _ := clientGet.Exists(key); ok {

				typ, err := clientGet.Type(key)

				if err != nil {
					fmt.Println("get the key " + key + "type FAILED")
					return
				}

				switch typ {

				case "set":
					for _, u := range value {

						if str, ok := u.(string); ok {
							/* act on str */
							if b, _ := clientGet.Sismember(key, []byte(str)); b {
								fmt.Println("the set key " + key + " don't contains the value " + str + " PASSED")
							} else {
								fmt.Println("the set key " + key + " contains the value " + str + " FAILED")
							}
						} else {
							/* not string */
						}
					}
				case "hash":

					for i := 0; i < len(value); i = i + 2 {

						field := value[i].(string)

						if b, _ := clientGet.Hexists(key, field); b {
							fmt.Println("the hash key " + key + " field " + field + " exists. FAILED")
						} else {
							fmt.Println("the hash key " + key + " don't contains the field " + field + " PASSED")
						}
					}

				default:
					fmt.Println("the " + typ + " can't supported now")
				}

			} else {
				fmt.Println("the key " + key + " is not exists now. PASSED")
			}
		} else {
			if ok, _ := clientGet.Exists(key); ok {
				fmt.Println("the key " + key + " is exists. FAILED")
			} else {
				fmt.Println("the key " + key + " is not exists now. PASSED")
			}
		}
		return
	}

	if ok, _ := clientGet.Exists(key); !ok {
		fmt.Println("the key " + key + " is not exists. FAILED")
		return
	}

	typ, err := clientGet.Type(key)

	if err != nil {
		fmt.Println("get the key " + key + " type FAILED")
		return
	}

	switch typ {

	case "set":
		for _, u := range value {

			if str, ok := u.(string); ok {
				/* act on str */
				if b, _ := clientGet.Sismember(key, []byte(str)); b {
					fmt.Println("the set key " + key + " contains the value " + str + " PASSED")
				} else {
					fmt.Println("the set key " + key + " don't contains the value " + str + " FAILED")
				}
			} else {
				/* not string */
			}
		}
	case "hash":

		for i := 0; i < len(value); i = i + 2 {

			field := value[i].(string)
			evalue := value[i+1].(string)

			if b, _ := clientGet.Hexists(key, field); b {

				rvalue, _ := clientGet.Hget(key, field)
				if strings.EqualFold(string(rvalue), evalue) {
					fmt.Println("the hash key " + key + " field " + field + " value " + evalue + " PASSED")
				} else {
					fmt.Println("the hash key " + key + " field " + field + " FAILED ")
					fmt.Println("please check infact value :" + string(rvalue))
					fmt.Println("expect value :" + evalue)
				}

			} else {
				fmt.Println("the hash key " + key + " don't contains the field " + field + " FAILED")
			}
		}

	default:
		fmt.Println("the " + typ + " can't supported now")
	}

}

type Config struct {
	Message_queue_ip string `yaml:"message-queue-ip"`
	Message_queue_port string `yaml:"message-queue-port"`
	Message_queue_password string `yaml:"message-queue-password"`
	Master_redis_ip string `yaml:"master-redis-ip"`
	Master_redis_port string `yaml:"master-redis-port"`
	Master_redis_password string `yaml:"master-redis-password"`
}

func loadConfig(configFile string) {

	buf, err := ioutil.ReadFile(configFile)

	if err != nil {
		fmt.Println("load config failed")
		return
	}
	var configp Config

	err = yaml.Unmarshal(buf, &configp)

	if err != nil {
		fmt.Println("yaml unmarshal fialed")
		return
	}

	clientPush.Addr = configp.Message_queue_ip + ":" + configp.Message_queue_port
	clientPush.Password = configp.Message_queue_password

	clientGet.Addr = configp.Master_redis_ip + ":" + configp.Master_redis_port
	clientGet.Password = configp.Master_redis_password

}

func main() {

	loadConfig("./config/config.yaml")

	// clean master redis 6379
	clientGet.Flush(true)
	clientPush.Set("state", []byte("1"))

	var testCasejson TestCaseJson
	var messageJson message.CommonMessageStruct

	fmt.Println("***************dispatcher test begin*************************")

	fileList, _ := ioutil.ReadDir("./testcases/")

	for i := 0; i < len(fileList); i++ {

		fmt.Println("**********************************")
		fmt.Println("test case name :" + fileList[i].Name())

		testCase, _ := ioutil.ReadFile("./testcases/" + strings.Trim(fileList[i].Name(), "\n"))

		//fmt.Println("%s", string(testCase))

		unmarshalErr := json.Unmarshal(testCase, &testCasejson)

		checkErr(unmarshalErr)

		json.Unmarshal([]byte(testCasejson.Message), &messageJson)
		//fmt.Println(testCasejson.Message)

		//lpush message_queue "{\"table_name\":\"ad\",\"status\":\"update\",\"content\":{\"id\":\"1\",\"ad_template_id\":\"2\"}}"
		err1 := clientPush.Lpush("message_queue", []byte(testCasejson.Message))

		if err1 != nil {
			fmt.Println("Lpush failed%s", err1.Error())
		}

		//wait dispatcher process the message_queue
		time.Sleep(8 * time.Second)

		m := testCasejson.Results.(map[string]interface{})

		for k, v := range m {
			switch vv := v.(type) {
			case string:
				//fmt.Println(k, "is string", vv)
				verifyRedisKeyValue(k, vv, messageJson.Status)
			case []interface{}:
				// fmt.Println(k, "is an array:")
				// for i, u := range vv {
				// 	fmt.Println(i, u)
				// }
				verifyRedisSetHashKeyValue(k, vv, messageJson.Status)
			default:
				fmt.Println(k, " is of a type I don't know how to handle")
			}
		}

	}

	fmt.Println("***************dispatcher test end*************************")

	//clean master redis(6379) for dump test
	clientGet.Flush(true)
}
